修改 update_user:接收 AuthenticatedUser 並做 owner 檢查
use crate::extractors::AuthenticatedUser;
pub async fn update_user(
    Extension(pool): Extension<PgPool>,
    Extension(mut redis): Extension<MultiplexedConnection>,
    AuthenticatedUser(claims): AuthenticatedUser,   // <- 新增
    Path(id): Path<i64>,
    Json(payload): Json<UpdateUser>,
) -> Result<impl IntoResponse, AppError> {
    // 1) 授權檢查:只有 owner 可以更新
    let caller_id: i64 = claims.sub.parse().map_err(|_| (StatusCode::UNAUTHORIZED, "invalid token sub".to_string()))?;
    if caller_id != id {
        return Err((StatusCode::FORBIDDEN, "forbidden".to_string()));
    }
    // 原先更新邏輯(查 existing、hash password、UPDATE ...)
    let existing = sqlx::query_as::<_, User>("SELECT id, username, email, password_hash, created_at, updated_at FROM users WHERE id = $1")
        .bind(id)
        .fetch_optional(&pool)
        .await
        .map_err(|e| internal_err(e))?;
}
修改 delete_user:同樣加入 AuthenticatedUser 與授權檢查
pub async fn delete_user(
    Extension(pool): Extension<PgPool>,
    Extension(mut redis): Extension<MultiplexedConnection>,
    AuthenticatedUser(claims): AuthenticatedUser,  // <- 新增
    Path(id): Path<i64>,
) -> Result<impl IntoResponse, AppError> {
    let caller_id: i64 = claims.sub.parse().map_err(|_| (StatusCode::UNAUTHORIZED, "invalid token sub".to_string()))?;
    if caller_id != id {
        return Err((StatusCode::FORBIDDEN, "forbidden".to_string()));
    }
    let res = sqlx::query!(
        r#"
        DELETE FROM users
        WHERE id = $1
        "#,
        id
    )
    .execute(&pool)
    .await
    .map_err(|e| internal_err(e))?;
}
另外的強化:把 owner 驗證放到 SQL
若擔心 race condition(TOCTOU),可以在 SQL 的 WHERE 同時帶上 caller_id,例如(DELETE ):
let res = sqlx::query!(
    r#"
    DELETE FROM users
    WHERE id = $1 AND id = $2
    "#,
    id, caller_id
)
.execute(&pool)
.await
.map_err(|e| internal_err(e))?;